﻿using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
using UnityEngine.Networking;
using System.Threading.Tasks;

public class HttpClient : HttpUtility
{
    /// <summary>
    /// һ����׼jsonӦ������ṹ
    /// </summary>
    public class Response
    {
        /// <summary>
        /// HTTP ����
        /// </summary>
        public UnityWebRequest req { get; private set; }
        /// <summary>
        /// HTTP ������״̬
        /// </summary>
        public UnityWebRequest.Result result { get; private set; }
        /// <summary>
        /// �Ƿ���������ͨ�Ŵ���
        /// </summary>
        public bool hasHttpError => result == UnityWebRequest.Result.ConnectionError || result == UnityWebRequest.Result.ProtocolError;
        /// <summary>
        /// ��·ͨ�Ŵ�����Ϣ
        /// </summary>
        public string httpError { get; protected set; }
        /// <summary>
        /// HTTP Ӧ��״̬��
        /// </summary>
        public long httpResponseCode { get; protected set; }
        /// <summary>
        /// HTTP Ӧ����ϢժҪ
        /// </summary>
        public string summary { get; protected set; }

        /// <summary>
        /// Ӧ�����Ľṹ��Ӧ�ò�����
        /// </summary>
        public class BodyObject
        {
            [JsonProperty("message")]
            public string message { get; set; }
            [JsonProperty("result")]
            public JRaw result { get; set; }
            [JsonProperty("requestId")]
            public string requestId { get; set; }
            [JsonProperty("succeed")]
            public bool succeed { get; set; }

            public T ParseData<T>()
            {
                try
                {
                    return JsonConvert.DeserializeObject<T>(result.Value<string>());
                }
                catch (Exception e)
                {
                    Debug.LogException(e);
                    return default(T);
                }
            }
        }
        /// <summary>
        /// Ӧ�����ķ����л���Ӧ�ò����ݶ���ʵ��
        /// </summary>
        public BodyObject body { get; protected set; }

        /// <summary>
        /// 应用层应答状态，若发生网络通信错误则固定为 -1
        /// </summary>
        public int status => (hasHttpError || !body.succeed) ? -1 : 0;

        public bool success => status == 0;
        /// <summary>
        /// 错误描述，若发生网络通信错误则返回网络通信错误信息，否则返回应用层错误信息
        /// </summary>
        public string error => hasHttpError ? httpError : body?.message;
        public Response(UnityWebRequest req)
        {
            this.req = req;
            result = req.result;
            httpError = req.error;
            httpResponseCode = req.responseCode;
            summary = $"HTTP {req.responseCode}: {req.downloadHandler.text}";
            if (summary.Length > 1024)
                summary = summary.Substring(0, 1024) + "...<truncated>";

            if (!hasHttpError)
            {
                try { body = JsonConvert.DeserializeObject<BodyObject>(req.downloadHandler.text); }
                catch (Exception e) { Debug.LogException(e); }
            }
        }
        public override string ToString() { return hasHttpError ? error : summary; }
    }

    /// <summary>
    /// 发起一条 Get 请求，可以拼接需要的参数在url上, 并请求并期待返回标准 json 格式数据
    /// </summary>
    /// <param name="url">请求地址</param>
    /// <param name="data">请求正文数据 json 格式</param>
    public async Task<Response> GetData(string url, Dictionary<string, string> headers, Dictionary<string, string> data)
    {
        var taskCom = new TaskCompletionSource<Response>();

        if (data != null)
        {
            StringBuilder builder = new StringBuilder();
            builder.Append(url);
            builder.Append("?");
            int i = 0;
            foreach (var item in data)
            {
                if (i > 0)
                    builder.Append("&");
                builder.AppendFormat("{0}={1}", item.Key, item.Value);
                i++;
            }
            url = builder.ToString();
        }

        Get(url, headers, (request) => {
            var resp = new Response(request);
            Debug.Log($"应答 {url} 返回: {resp}");
            taskCom.SetResult(resp);
        });
        return await taskCom.Task;
    }

    /// <summary>
    /// 发起一条 post 请求并期待返回标准 json 格式数据
    /// 可以参数为json数据，也可以为 WWWForm （首选json格式）
    /// </summary>
    /// <param name="url">请求地址</param>
    /// <param name="data">请求正文数据 json 格式</param>
    public async Task<Response> PostData(string url, Dictionary<string, string> headers, object data)
    {
        string str = "{}";
        byte[] body = Encoding.UTF8.GetBytes(str);
        if (data is WWWForm)
        {
            body = (data as WWWForm).data;
        }
        else if (data != null)
        {
            str = JsonConvert.SerializeObject(data);
            body = Encoding.UTF8.GetBytes(str);
        }

        var taskCom = new TaskCompletionSource<Response>();
        Post(url, headers, body, (request) => {
            var resp = new Response(request);
            Debug.Log($"应答 {url} 返回: {resp}");
            taskCom.SetResult(resp);
        });
        return await taskCom.Task;
    }
}
